home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
System Booster
/
System Booster.iso
/
Commodities
/
RMBShift
/
RMBShift.asm
< prev
next >
Wrap
Assembly Source File
|
1996-09-26
|
15KB
|
549 lines
* RMBShift
* By Preben Nielsen
*
* This small program makes it possible for the right mouse-button to
* act as a shift key. This means that it will be possible to select
* multiple icons on the workbench without having to press a Shift-Key.
*
* Once installed, the program only uses 268 bytes of memory.
* To get back to normal simply run the program again.
*
* NOTE: There's no need to 'RUN' or 'RUNBACK' this program from the
* CLI. It terminates immediately.
*
*HISTORY
* Made with Hisoft V2.12
*
* V1.0 01-Sep-91: First attempt. Works of course.
* V2.0 22-Sep-91: Now works completely different.
OPT O+
OPT O1+ ; Tells when a branch could be optimised to short
OPT i+ ; Tells when '#' is probably missing
incdir "AsmInc:"
include "P.i"
include "relMacros.i"
include "exec/exec_lib.i"
include "exec/io.i"
include "exec/memory.i"
include "exec/interrupts.i"
include "devices/input.i"
include "devices/inputevent.i"
include "libraries/dosextens.i"
include "libraries/dos_lib.i"
include "intuition/intuition.i"
DB EQUR A4
dcDeclare A4
dcAPtr PProcess
dcAPtr WBMsg
dcAPtr DosBase
dcAPtr HMem
dcEnd
Start dcAlloc ; Allocate memory for variables
dcReset ; Clear the memory
Prepare Exec_Call
suba.l A1,A1
CallLib FindTask ; Find us
move.l D0,PProcess(DB)
movea.l D0,A2
tst.l pr_CLI(A2)
bne.S GetLibs
WBStart lea pr_MsgPort(A2),A0
CallLib WaitPort ; wait for a message
lea pr_MsgPort(A2),A0
CallLib GetMsg ; then get it
move.l D0,WBMsg(DB) ; save it for later reply
GetLibs lea DosName(PC),A1
CallLib OldOpenLibrary
move.l D0,DosBase(DB)
beq.S Error
lea IHSName(PC),A1
Call FindThisPort
beq.S DoInstall
DoRemove moveq #REMOVED,D7
lea IHS(PC),A0
lea PSEndIHS1(PC),A1
lea PSEndIHS2(PC),A2
Call RemoveHandler
beq.S ShowMsg
moveq #CANTREMOVE,D7
bra.S ShowMsg
DoInstall moveq #INSTALLED,D7
lea IHS(PC),A0
lea PSPrepIHS1(PC),A1
lea PSPrepIHS2(PC),A2
Call InstallHandler
beq.S ShowMsg
moveq #CANTINSTALL,D7
ShowMsg move.l D7,D0
Call CONMsg
Error
Exit Prepare Exec_Call
FreeDos move.l DosBase(DB),D0
beq.S ReplyWB
move.l D0,A1
CallLib CloseLibrary
ReplyWB move.l WBMsg(DB),D2
beq.S AllDone
CallLib Forbid ; We were started from WB
movea.l D2,A1
CallLib ReplyMsg ; Reply WBMessage
AllDone dcFree
moveq #0,D0
rts
*»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
*»»» Console message routines »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
*»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
FHandle EQUR D5
*»»» Call: D0 = Msg-number
*»»» Writes a general copyright message and then a more specific message.
*»»» Writes to standard output when run from CLI, and opens its own window
*»»» when run from Workbench.
CONMsg Push D0-D7/A0-A6
Prepare Dos_Call
move.l D0,D4
moveq #0,D6
CallLib Output
move.l D0,FHandle
bne.S 1$
moveq #1,D6
lea CONName(PC),A0
move.l A0,D1
move.l #MODE_OLDFILE,D2
CallLib Open
move.l D0,FHandle
beq.S 2$
1$ moveq #INFOMSG,D0
Call SendMsg
move.l D4,D0
Call SendMsg
tst.l D6
beq.S 2$
moveq #127,D1
CallLib Delay
move.l FHandle,D1
CallLib Close
2$ Pop D0-D7/A0-A6
rts
*»»» Call: D0 = Msg-number
SendMsg neg.l D0
lsl.l #1,D0
lea CONMsgTable(PC),A0
add.w 0(A0,D0),A0
move.l A0,D2
moveq #-1,D3
1$ addq.l #1,D3
tst.b (A0)+
bne.S 1$
move.l FHandle,D1
Prepare Dos_Call
CallLib Write
rts
INFOMSG =0
INSTALLED =-1
REMOVED =-2
CANTINSTALL =-3
CANTREMOVE =-4
CONText MACRO
dc.w \1-CONMsgTable
ENDM
CONMsgTable CONText Msg
CONText Msg1
CONText Msg2
CONText Msg3
CONText Msg4
CONName dc.b 'CON:100/60/330/63/RMBShift',0
Msg dc.b 10,$9B,'0;33m RMBShift V2.0',10
dc.b $9B,'0;31m 1991 by ',$9B,'0;33mPreben Nielsen',$9B,'0;31m',10,' ',0
Msg1 dc.b 'has now been installed...',10,0
Msg2 dc.b 'has now been removed...',10,0
Msg3 dc.b "Error: Can't install handler",10,0
Msg4 dc.b "Error: Can't remove handler",10,0
EVEN
*»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
*»»» End of Console message routines »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
*»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
*»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
*»»» Inputhandler removal and installation routines »»»»»»»»»»»»»»»»»»»»»»»»
*»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
rtsValue EQUR D7
*»»» This is general-purpose inputhandler removal-routine
*»»» It only needs an ihs with a port-name to remove the handler
*»»» Call: A0 = ihs
*»»» A1 = first ihs-installation-routine or NULL
*»»» A2 = second ihs-installation-routine or NULL
*»»» Return: D0 = 0 means succes
RemoveHandler Push D1/rtsValue/A0-A3/A6
moveq #-1,rtsValue
move.l A2,A3
move.l A0,A2
move.l A1,D1
beq.S 1$
jsr (A1) ; A0 = ihs
beq.S 2$
move.l D0,A2
1$ move.l A2,A0
Prepare Exec_Call
moveq #IND_REMHANDLER,D0
Call TellInputDevice
move.l D0,rtsValue
bne.S 2$
lea ihs_Port(A2),A1
CallLib RemPort
moveq #0,D0
bra.S 3$
2$ moveq #-1,D0
3$ move.l A3,D1
beq.S 4$
move.l A2,A0
jsr (A3) ; A0 = ihs, D0 = 0 means succes
4$ move.l rtsValue,D0
Pop D1/rtsValue/A0-A3/A6
rts
*»»» This is general-purpose inputhandler installation-routine
*»»» It only needs an ihs with a port-name to install the handler
*»»» Call: A0 = ihs
*»»» A1 = first ihs-installation-routine or NULL
*»»» A2 = second ihs-installation-routine or NULL
*»»» Return: D0 = 0 means succes
InstallHandler Push D1/rtsValue/A0-A3/A6
moveq #-1,rtsValue
move.l A2,A3
move.l A0,A2
move.l A1,D1
beq.S 1$
jsr (A1) ; A0 = ihs
beq.S 2$
move.l D0,A2
1$ move.l A2,A0
moveq #IND_ADDHANDLER,D0
Call TellInputDevice
move.l D0,rtsValue
bne.S 2$
lea ihs_Port(A2),A1
move.l ihs_PortName(A2),MP+LN_NAME(A1) ;MsgPort->mp_Node.ln_Name=Name;
clr.b MP+LN_PRI(A1) ;MsgPort->mp_Node.ln_Pri =0;
move.b #NT_MSGPORT,MP+LN_TYPE(A1) ;MsgPort->mp_Node.ln_Type=NT_MSGPORT;
move.b #PA_IGNORE,MP_FLAGS(A1) ;MsgPort->mp_Flags =PA_IGNORE;
Prepare Exec_Call
CallLib AddPort
moveq #0,D0
bra.S 3$
2$ moveq #-1,D0
3$ move.l A3,D1
beq.S 4$
move.l A2,A0
jsr (A3) ; A0 = ihs, D0 = 0 means succes
4$ move.l rtsValue,D0
Pop D1/rtsValue/A0-A3/A6
rts
*»»» Open the input device. Set up the I/O block to add or remove the
*»»» input handler, and send the request to the input device. Finally,
*»»» close the device
*»»» Call: A0 = ihs
*»»» D0 = Function to perform (IND_ADDHANDLER/IND_REMHANDLER)
*»»» Return: D0 = 0 means succes
dcDeclare A5
dcArea IReq,IOSTD_SIZE
dcArea IPort,MP_SIZE
dcEnd
TellInputDevice dcAlloc
dcReset
Push D1-D2/rtsValue/A0-A3/A6
Prepare Exec_Call
moveq #-1,rtsValue
move.l D0,D2
move.l A0,A2
lea IPort(A5),A3
move.b #NT_MSGPORT,MP+LN_TYPE(A3) ; mp_Node.ln_Type=NT_MSGPORT;
move.b #PA_SIGNAL,MP_FLAGS(A3) ; mp_Flags =PA_SIGNAL;
moveq #-1,D0
CallLib AllocSignal
move.b D0,MP_SIGBIT(A3) ; mp_SigBit =MPSigBit;
bmi.S 2$
suba.l A1,A1
CallLib FindTask
move.l D0,MP_SIGTASK(A3) ; mp_SigTask =FindTask(0);
lea MP_MSGLIST(A3),A0
NEWLIST A0
lea IReq(A5),A1
move.l A3,IO+MN_REPLYPORT(A1) ; ExtReq->io_Message.mn_ReplyPort =taskReplyPort;
move.b #NT_MESSAGE,IO+MN+LN_TYPE(A1) ; ExtReq->io_Message.mn_Node.ln_Type=NT_MESSAGE;
lea InputName(PC),A0 ; input.device
moveq #0,D0 ; unit#
moveq #0,D1 ; flags
CallLib OpenDevice
tst.w D0 ; flag: error if > 0
bne.S 1$
lea IReq(A5),A1
move.w D2,IO_COMMAND(A1)
lea ihs_Interrupt(A2),A0
move.l A0,IO_DATA(A1)
CallLib DoIO
move.l D0,rtsValue
lea IReq(A5),A1
CallLib CloseDevice
1$ move.b MP_SIGBIT(A3),D0
CallLib FreeSignal
2$ move.l rtsValue,D0
Pop D1-D2/rtsValue/A0-A3/A6
dcFree
rts
*»»» Each handler should have such a pair of installation-routines.
*»»» The first one is passed to InstallHandler in A1, and it
*»»» is called immediately when entering InstallHandler.
*»»» The second one is passed to InstallHandler in A2, and it
*»»» is called if installation of handler and message-port succeeds.
*»»» -----------------------------------------------------------------
*»»» Call: A0 = ihs
*»»» Return: D0 has to point to ihs to be used when installation proceeds.
*»»» If D0 = 0 then installation is aborted.
PSPrepIHS1 Push D1-D2/A0-A1/A6
Prepare Exec_Call
lea IntuiName(PC),A1
CallLib OldOpenLibrary ; Hmm, I never close it again.
move.l D0,D2
beq.S 2$
move.l #HandlerSize,D0
move.l #MEMF_PUBLIC|MEMF_CLEAR,D1
CallLib AllocMem
move.l D0,HMem(DB)
beq.S 2$
move.l D0,A1
lea IHS(PC),A0
move.l #HandlerSize,D0
Push D0/A0-A1
CallLib CopyMem
Pop D0/A0-A1
move.l D0,ihs_Length(A1) ; This will enable removal by other programs
move.l D2,IntuiBase-IHS(A1) ; Give IntuiBase value
lea HandlerCode-IHS(A1),A0
move.l A0,ihs_Interrupt+IS_CODE(A1) ; ihs_Interrupt.is_Code = Handler
clr.l ihs_Interrupt+IS_DATA(A1) ; ihs_Interrupt.is_Data = 0
lea IHSName-IHS(A1),A0
move.l A0,ihs_PortName(A1) ; ihs_PortName = IHSName
move.b #HPRI,ihs_Interrupt+LN_PRI(A1) ; ihs_Interrupt.is_Node.ln_Pri = HPRI
move.l A1,D0
2$ Pop D1-D2/A0-A1/A6
rts
*»»» Call: A0 = ihs
*»»» D0 = 0 means everything went perfect
*»»» -1 means something went wrong during installation
PSPrepIHS2 Push D0-D1/A0-A1/A6
tst.l D0
beq.S 1$
move.l HMem(DB),D0
beq.S 1$
move.l D0,A1
move.l #HandlerSize,D0
Prepare Exec_Call
CallLib FreeMem
1$ Pop D0-D1/A0-A1/A6
rts
*»»» Each handler should have such a pair of ending-routines.
*»»» The first one is passed to RemoveHandler in A1, and it
*»»» is called immediately when entering RemoveHandler.
*»»» The second one is passed to RemoveHandler in A2, and it
*»»» is called if removal of handler and message-port succeeds.
*»»» -----------------------------------------------------------------
*»»» Call: A0 = ihs
*»»» Return: D0 has to point to ihs to be used when removal proceeds
*»»» If D0 = 0 then removal is aborted
PSEndIHS1 Push A1
lea IHSName(PC),A1
Call FindThisPort
Pop A1
rts
*»»» Call: A0 = ihs
*»»» D0 = 0 means everything went perfect
*»»» -1 means something went wrong during removal
PSEndIHS2 Push D0-D1/A0-A1/A6
tst.l D0
bmi.S 1$
Prepare Exec_Call
move.l ihs_Length(A0),D0
move.l A0,A1
CallLib FreeMem
1$ Pop D0-D1/A0-A1/A6
rts
*»»» Call: A1 = Portname
*»»» Return: D0 = Port or NULL (cc reflects result also)
FindThisPort Push D1-D2/A0-A1/A6
Prepare Exec_Call
move.l A1,D2
CallLib Forbid
move.l D2,A1
CallLib FindPort
move.l D0,D2
CallLib Permit
move.l D2,D0
Pop D1-D2/A0-A1/A6
rts
*»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
*»»» Input-handler start »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
*»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
ihs_Port =0
ihs_Interrupt =MP_SIZE
ihs_ID =MP_SIZE+IS_SIZE
ihs_Length =MP_SIZE+IS_SIZE+4
ihs_Flags =MP_SIZE+IS_SIZE+8
ihs_PortName =MP_SIZE+IS_SIZE+10
ihs_LocalArea =MP_SIZE+IS_SIZE+14
ihs_SIZE =MP_SIZE+IS_SIZE+14
ihs_Start MACRO
dcb.b MP_SIZE ; Message-Port structure
dcb.b IS_SIZE ; Interrupt structure
dc.l 'P_IH' ; ID
dc.l 0 ; Length of handler
dc.w 0 ; Flags
dc.l 0
ENDM
HPRI =55
HDisabled =0
HNoExtRemoval =1
*»»» This is the handler-block
IHS ihs_Start
*»»» Put local data here
IntuiBase dc.l 0
State dc.w 0
ENABLED =0
DOING_SHIFT =1
*»»» IHS name
IHSName dc.b 'RMBShift V2.0 Port',0
EVEN
*»»» For each event in the event list:
*»»» If we were waiting for this event then signal the task.
*»»» When all the events have been checked, return the event list so that
*»»» others can do their things.
EList EQUR A0
Event EQUR A1
Next =ie_NextEvent
Class =ie_Class
Code =ie_Code
Qual =ie_Qualifier
*»»» Call: A0 = List of InputEvents
*»»» A1 = HandlerData (not used)
HandlerCode Push Event/EList/A2
move.l EList,Event
ieLoop move.l Event,D0
beq NoMoreEvents
*»»» Is it a RAWMOUSE event ?
cmpi.b #IECLASS_RAWMOUSE,Class(Event)
bne.S KeepEvent
*»»» Is it an RMB press event ?
cmpi.w #IECODE_RBUTTON,Code(Event)
beq.S PressRMB
*»»» Is it an RMB release event ?
cmpi.w #IECODE_UP_PREFIX|IECODE_RBUTTON,Code(Event)
bne.S KeepEvent
*»»» End the event modifying state
ReleaseRMB lea State(PC),A2
bclr #DOING_SHIFT,(A2)
beq.S KeepEvent
bra.S KillEvent
PressRMB
*»»» Is the Left mousebutton pressed also ?
btst #IEQUALIFIERB_LEFTBUTTON-8,Qual(Event)
beq.S CheckRMBShift
*»»» Now either enable or disable this handler.
ToggleState lea State(PC),A2
bchg #ENABLED,(A2)
bra.S UseAndKillEvent
*»»» See if we can use the RMB as a SHIFT key.
CheckRMBShift btst #ENABLED,State(PC)
bne.S NoMoreEvents
*»»» Is there an active screen ?
move.l IntuiBase(PC),A2
move.l ib_ActiveScreen(A2),D0
beq.S UseAndKillEvent
move.l D0,A2
*»»» Is the mouse in the screens titlebar ?
move.b sc_BarHeight(A2),D0
ext.w D0
cmp.w sc_MouseY(A2),D0
bgt.S KeepEvent
*»»» Is there an active window ?
move.l IntuiBase(PC),A2
move.l ib_ActiveWindow(A2),D0
beq.S UseAndKillEvent
move.l D0,A2
*»»» Is the RMBTRAP flag set ?
moveq #RMBTRAP>>16,D0
and.w wd_Flags(A2),D0
beq.S UseAndKillEvent
*»»» The RMBTRAP flag is set, but does the window really want to
*»»» know about mouse-button events ?
moveq #MOUSEBUTTONS,D0
and.l wd_IDCMPFlags(A2),D0
bne.S KeepEvent
*»»» Enter the event modifying state
UseAndKillEvent lea State(PC),A2
bset #DOING_SHIFT,(A2)
*»»» Remove this event by making it into a NULL event
KillEvent clr.w Class(Event)
*»»» Just move on to next Event
KeepEvent btst #DOING_SHIFT,State(PC)
beq.S 1$
*»»» Clear the RBUTTON qualifier
bclr #IEQUALIFIERB_RBUTTON-8,Qual(Event)
*»»» Set a SHIFT qualifier
bset #IEQUALIFIERB_LSHIFT,Qual+1(Event)
1$ move.l Next(Event),Event
bra ieLoop
*»»» Lets return the list
NoMoreEvents move.l EList,D0
Pop Event/EList/A2
rts
HandlerSize = *-IHS
*»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
*»»» Input-handler end »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
*»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
*»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
*»»» Data-definition start»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
*»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
DosName dc.b 'dos.library',0
IntuiName dc.b 'intuition.library',0
InputName dc.b 'input.device',0
END